﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "CmdCreateFamilyInstance.h"
#include "CommandIds.h"
#include "CommandRegister.h"
#include "Action/ActionCreatePointFamilyInstance.h"
#include "IUiDocument.h"
#include "IUiDocumentViewManager.h"
#include "IDocumentManager.h"
#include "IFileExtensions.h"
#include "UiCommonDialog.h"
#include "GbmpFileSystem.h"
#include "IFamily.h"
#include "FilePath.h"
#include "IFamilyType.h"
#include "NotificationUtils.h"
#include "IUserTransaction.h"
#include "IElementBasicInformation.h"
#include "GcmpBuiltInCategoryUniIdentities.h"
#include "IMeshDiscretizeOptions.h"
#include "IDocumentManager.h"
#include "IFamilyManager.h"
#include "FamilyUtils.h"
#include "FamilyLoadOptionsDefaultImpl.h"
#include "UiDocumentViewUtils.h"
#include "CommandParameters.h"
#include "JournalUtils.h"
#include "EnableCompileWarning_The_LAST_IncludeInCpp.h" 

using namespace std;
using namespace Sample;
using namespace gcmp;
using namespace gfam;


REGISTER_COMMAND(CmdCreateFamilyInstance);
CmdCreateFamilyInstance::CmdCreateFamilyInstance() : CommandBase(ID_LOAD_AND_CREATE_FAMILY_INSTANCE, true)
{
}

CmdCreateFamilyInstance::~CmdCreateFamilyInstance()
{
}

bool CmdCreateFamilyInstance::IsEnabled() const
{
    return UiDocumentViewUtils::GetCurrentDocument() != nullptr;
}

bool CmdCreateFamilyInstance::IsVisible() const
{
    return true;
}

gcmp::OwnerPtr<gcmp::IAction> CmdCreateFamilyInstance::ExecuteCommand(const gcmp::CommandParameters& cmdParams)
{
    IUiDocumentViewManager* pUiDocumentViewManager = IUiDocumentViewManager::Get();
    IUiDocument* pUiDocument =  pUiDocumentViewManager->GetCurrentUiDocument();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pUiDocument, L"pUiDocument为空", L"GDMP", L"2023-09-30");
    IDocument* pMainDoc = pUiDocument->GetDbDocument();

    // get family file path
    std::wstring filePath = L"";
    const int nCmdParamsCnt = (int)cmdParams.size();
    if (nCmdParamsCnt != 0 && gcmp::JournalUtils::IsInReplay())
    {
        //回放日志，从CommandParameters解析测试脚本程序集路径
        auto itor = cmdParams.find(L"FilePath");
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(itor != cmdParams.end(), L"回放所需的文件路径不存在", L"GDMP", L"20223-09-30");
        std::wstring path = itor->second.AsWString();
        if (!gcmp::FilePath::IsRelativePath(path))
        {
            // 全路径
            filePath = path;
        }
        else
        {
            // 相对于当前回放日志的相对路径
            gcmp::FilePath replayJSPath(gcmp::JournalUtils::GetReplayFilePath());
            filePath = FilePath::Combine(replayJSPath.GetDirectoryName(), path);
        }
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(FileInfo(filePath).IsFile(), L"打开文件命令在回放时没有找到指定的文件：" + filePath, L"GDMP", L"2023-09-30");
    }
    else
    {
        wstring filter = std::wstring(L"Family(*") + IDocumentManager::Get()->GetFileExtensions()->GetDefaultFamilyFileExt() + L")";
        filePath = UiCommonDialog::ShowOpenFileDialog(GBMP_TR(L"加载族文档"), gcmp::FileSystem::GetWorkingDirPath(), filter);
    }
    if (filePath.empty())
    {
        return nullptr;
    }

    // check if family is loaded
    FilePath filePathObj(filePath);
    wstring familyName = filePathObj.GetFileNameWithoutExtension();
    IFamily* pFamily = IFamily::GetFamilyByName(pMainDoc, familyName);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(!pFamily, L"此族已加载", L"GDMP", L"2023-09-30");

    // load family
    bool needSetPrecision = false;//是否需要设置精度
    wstring errorMsg = L"";
    if (!LoadFamily(pMainDoc, filePath, pFamily, errorMsg, needSetPrecision))
    {
        UiCommonDialog::ShowMessageBox(GBMP_TR(L"加载族文档"), errorMsg, (int)UiCommonDialog::ButtonType::OK);
        return nullptr;
    }

    NotificationUtils::PostNotification(NotificationTypes::InfomationNotificationType, GBMP_TR(L"加载族完成。"));

    // create family instance
    std::vector<const IFamilyType*> pFamilyTypes = pFamily->GetFamilyTypes();
    const UniIdentity& familyCategoryUid = pFamily->GetBasicInformation()->GetCategoryUid();
    if (familyCategoryUid == BuiltInCategoryUniIdentities::BICU_POINT_FAMILY)
    {
        return NEW_AS_OWNER_PTR(ActionCreatePointFamilyInstance, pFamily->GetElementId(), 
            pFamilyTypes.at(0)->GetName(), needSetPrecision);
    }
    else
    {
        UiCommonDialog::ShowMessageBox(GBMP_TR(L"创建族实例"), L"不支持该类型族实例的创建", (int)UiCommonDialog::ButtonType::OK);
    }

    return nullptr;
}

bool CmdCreateFamilyInstance::LoadFamily(IDocument* pDocument, std::wstring filePath, IFamily* &pFamily, std::wstring& errorMsg, bool& needSetPrecision)
{
    needSetPrecision = false;//是否需要设置精度
    errorMsg = L"";
    gcmp::OwnerPtr<IUserTransaction> opUt = IUserTransaction::Create(pDocument, (GBMP_TR(L"加载族")));

    LoadFamilyInfos familyInfos(filePath);
    FamilyLoadOptionsDefaultImpl familyLoadOptions(FamilyFoundStrategy::FF_Create);
    pFamily = FamilyUtils::LoadFamily(pDocument, familyInfos, errorMsg, &familyLoadOptions);
    if (!pFamily)
    {
        opUt->Rollback();
        return false;
    }

    //如果族设置有缩放比例，则修改文档级离散精度。
    DocumentLoadOptions docLoadOptions(false, false, false, false);
    DocumentLoadResult docLoadResult;
    std::set<std::wstring> unrecognizedAssemblies;
    IDocument* pFamilydoc = IDocumentManager::Get()->OpenDocument(filePath, docLoadOptions, docLoadResult, nullptr, &unrecognizedAssemblies);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pFamilydoc, L"没有打开族文件", L"GDMP", L"2023-09-30");
    IFamilyManager* pFamilyMgr = IFamilyManager::Get(pFamilydoc);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pFamilyMgr, L"没有打开族管理器", L"GDMP", L"2023-09-30");
    double famScale = pFamilyMgr->GetScale();
    if (famScale > 100)
    {
        needSetPrecision = true;
        //设置文档级的离散精度
        gcmp::IMeshDiscretizeOptions* pMeshDiscretizeOptions = gcmp::IMeshDiscretizeOptions::Get();
        if (nullptr != pMeshDiscretizeOptions)
        {
            pMeshDiscretizeOptions->SetMeshDiscretizePrecision(0.1, gcmp::Constants::MATH_PI / 10);
        }
    }
    IDocumentManager::Get()->CloseDocument(pFamilydoc->GetRuntimeId());

    std::vector<const IFamilyType*> pFamilyTypes = pFamily->GetFamilyTypes();
    if (pFamilyTypes.empty())
    {
        opUt->Rollback();
        errorMsg = L"无效的族文档，不存在族类型";
        return false;
    }

    opUt->Commit();
    return true;
}
